package DAO;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import Pojo.Historico;
import Pojo.Turma;
import Pojo.Aluno;
import Pojo.Disciplina;

/** Classe HistoricoDao
 * Essa classe implementa a interface HistoricoDao para comunicar com arquivo.
 * @author Thiago de Sousa Silveira
 *
 */
public class HistoricoDaoImplArquivo implements HistoricoDao{
	/** Lista de Históricos*/
	private List<Historico> listaHistoricos;
	
	/** Atributo constante com o endereço do arquivo onde será armazenada os dados.*/
	private static final String nomeArquivo = "Arquivos/Historicos.txt";
	
	/** Atributo onde é guardado o próximo id para inserção na lista.*/
	private int proximoId;

	/**
	 * Construtor da classe com um identificador indicando que não é necessário buscar dados do arquivo
	 * @param identificador
	 */
	public HistoricoDaoImplArquivo(int identificador){
		this.listaHistoricos = new ArrayList<Historico>();
		this.proximoId=0;
	}
	
	/**
	 * Construtor da classe que busca dados no arquivo
	 */
	public HistoricoDaoImplArquivo(){
		this.listaHistoricos = new ArrayList<Historico>();
		this.proximoId=0;
		this.buscarArmazenamento();
	}
	
	/**
	 * Getter do próximo id do HistóricoDao
	 * @return próximo id disponível
	 */
	public int getProximoId(){
		return(this.proximoId);
	}
	
	/**
	 * Lista dos Históricos. 
	 * @return Lista dos Históricos.
	 */
	public List<Historico> getListaHistoricos(){
		return(this.listaHistoricos);
	}
	
	/**
	 * Busca Armazenamento no arquivo, trata os dados e monta a lista dos históricos.
	 */
	private void buscarArmazenamento(){
		try{
			this.listaHistoricos = new ArrayList<Historico>();
			FileReader arq = new FileReader(nomeArquivo);		//Cria objeto arquivo
		    BufferedReader lerArq = new BufferedReader(arq);	//Cria objeto de leitura
		    String linha=lerArq.readLine();
		    Historico historico;
		    String dados[];
		    Aluno aluno;
		    Disciplina disciplina;
		    
		    while (linha != null) {
		    	dados = linha.split("\t");
		    	aluno = buscarAluno(Integer.parseInt(dados[3]));
		    	disciplina = buscarDisciplina(Integer.parseInt(dados[4]));
		    	historico = new Historico(Integer.parseInt(dados[0]),Double.parseDouble(dados[1]),Integer.parseInt(dados[2]),aluno,disciplina);
		    	this.listaHistoricos.add(historico);
		    	linha = lerArq.readLine();						//Lê as linhas.
		    	this.proximoId=Integer.parseInt(dados[0]);
		    }
		    this.proximoId++;
		    
		    arq.close();										//Fechando o arquivo
		}catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
	}
	
	/**
	 * Busca no armazenamento usando o id de um aluno. É usado para quando não se quer carregar os dados para a lista.
	 * @param idAluno
	 * @return Lista de Históricos
	 */
	public List<Historico> buscarArmazenamentoProcurarPorAluno(int idAluno){
		try{
			FileReader arq = new FileReader(nomeArquivo);		//Cria objeto arquivo
		    BufferedReader lerArq = new BufferedReader(arq);	//Cria objeto de leitura
		    String linha=lerArq.readLine();
		    Historico historico;
		    String dados[];
		    List<Historico> listaHistoricos = new ArrayList<Historico>();
		    
		    while (linha != null) {
		    	dados = linha.split("\t");
		    	if (Integer.parseInt(dados[3])==idAluno){
		    		historico = new Historico(Integer.parseInt(dados[0]),Double.parseDouble(dados[1]),Integer.parseInt(dados[2]));
		    		listaHistoricos.add(historico);
		    	}
		    	linha = lerArq.readLine();						//Lê as linhas.
		    }
		    arq.close();										//Fechando o arquivo
		    return(listaHistoricos);
		}catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
		return(null);
	}
	
	/**
	 * Busca no armazenamento usando o id de uma disciplina. É usado para quando não se quer carregar os dados para a lista.
	 * @param idDisciplina
	 * @return Lista de Históricos
	 */
	public List<Historico> buscarArmazenamentoProcurarPorDisciplina(int idDisciplina){
		try{
			FileReader arq = new FileReader(nomeArquivo);		//Cria objeto arquivo
		    BufferedReader lerArq = new BufferedReader(arq);	//Cria objeto de leitura
		    String linha=lerArq.readLine();
		    Historico historico;
		    String dados[];
		    List<Historico> listaHistorico = new ArrayList<Historico>();
		    
		    while (linha != null) {
		    	dados = linha.split("\t");
		    	if (Integer.parseInt(dados[4])==idDisciplina){
		    		historico = new Historico(Integer.parseInt(dados[0]),Double.parseDouble(dados[1]),Integer.parseInt(dados[2]));
		    		listaHistorico.add(historico);
		    	}
		    	linha = lerArq.readLine();						//Lê as linhas.
		    }
		    arq.close();										//Fechando o arquivo
		    return(listaHistorico);
		}catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
		return(null);
	}
	
	/**
	 * Método usado para salvar a lista do arquivo. O arquivo é sobrescrito nesse método.
	 */
	private void salvarArmazenamento(){
		try {
			BufferedWriter out = new BufferedWriter(new FileWriter(nomeArquivo));
			Iterator<Historico> i = listaHistoricos.iterator();
			
			Historico historico;
			while(i.hasNext()){
				historico = (Historico) i.next();
				out.write(historico.toString());
			}
			
			out.close();
		} catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
	}
	
	/**
	 * Método de adicionar Histórico na lista. 
	 * É verificado se ele o código já existe, pois se existir não pode ser histórico.
	 * Após inserir, o método "salvarArmazenamento()" é chamado
	 * @param historico
	 * @return true se foi possível inserir ou falso se ele foi encontrado na lista.
	 */
	public boolean adicionarHistorico(Historico historico){
		Iterator<Historico> i = listaHistoricos.iterator();
		Historico historicoComparacao;
		while(i.hasNext()){
			historicoComparacao = (Historico) i.next();
			if (historicoComparacao.getIdHistorico() == historico.getIdHistorico()){
				return(false);
			}
		}
		this.listaHistoricos.add(historico);
		this.proximoId++;
		this.salvarArmazenamento();
		return(true);
	}
	
	/**
	 * Método para remover histórico da lista. 
	 * Após remover o método "salvarArmazenamento" é chamado
	 * @param historico
	 * @return true se a histórico foi encontrado na lista para ser removido ou false se ele não foi encontrado.
	 */
	public boolean removerHistorico(Historico historico){
		Iterator<Historico> i = listaHistoricos.iterator();
		Historico historicoComparacao;
		boolean resultado;
		while(i.hasNext()){
			historicoComparacao = (Historico) i.next();
			if (historicoComparacao.getIdHistorico() == historico.getIdHistorico()){
				resultado = this.listaHistoricos.remove(historicoComparacao);
				this.salvarArmazenamento();
				return(resultado);
			}
		}
		return(false);
	}
	
	/**
	 * Pesquisa de Alunos passando o aluno e a disciplina
	 * @param idAluno
	 * @param idDisciplina
	 * @return Aluno cujo cpf é o que foi passado, ou um null indicando que nenhum aluno foi encontrado
	 */
	public Historico procurarPorAlunoEDisciplina(int idAluno, int idDisciplina){
		Iterator<Historico> i = this.listaHistoricos.iterator();
		Historico historicoComparacao;
		
		while(i.hasNext()){
			historicoComparacao = (Historico) i.next();
			if ((historicoComparacao.getAluno().getIdAluno() == idAluno)&&(historicoComparacao.getDisciplina().getIdDisciplina()==idDisciplina)){
				return(historicoComparacao);
			}
		}
		return(null);
	}
	
	/**
	 * Método para buscar o Aluno que está relcionado com Historico
	 * @param idAluno
	 * @return Aluno
	 */
	private Aluno buscarAluno(int idAluno){
		AlunoDaoImplArquivo alunoDaoImplArquivo = new AlunoDaoImplArquivo(idAluno);
		return(alunoDaoImplArquivo.buscarArmazenamentoProcurarPorId(idAluno));
	}
	
	/**
	 * Método para buscar a Disciplina que está relcionado com  Histórico
	 * @param idDisciplina
	 * @return Disciplina
	 */
	private Disciplina buscarDisciplina(int idDisciplina){
		DisciplinaDaoImplArquivo disciplinaDaoImplArquivo = new DisciplinaDaoImplArquivo(idDisciplina);
		return(disciplinaDaoImplArquivo.buscarArmazenamentoProcurarPorId(idDisciplina));
	}
}
